home *** CD-ROM | disk | FTP | other *** search
/ LiquidLibrary 2005 February / LiquidLibrary 2005 February - Disc 1.iso / pc / Portfolio Browser / Filters / PDF / LIB / pdf_main.ps < prev    next >
Text File  |  2003-01-03  |  23KB  |  776 lines

  1. %    Copyright (C) 1994, 2000 Aladdin Enterprises.  All rights reserved.
  2. % This software is licensed to a single customer by Artifex Software Inc.
  3. % under the terms of a specific OEM agreement.
  4.  
  5. % $RCSfile$ $Revision$
  6. % pdf_main.ps
  7. % PDF file- and page-level operations.
  8.  
  9. /.setlanguagelevel where { pop 2 .setlanguagelevel } if
  10. .currentglobal true .setglobal
  11. /pdfdict where { pop } { /pdfdict 100 dict def } ifelse
  12. pdfdict begin
  13.  
  14. % Patch in an obsolete variable used by some third-party software.
  15. /#? false def
  16.  
  17. % Test whether the current output device handles pdfmark.
  18. /.writepdfmarkdict 1 dict dup /pdfmark null put readonly def
  19. /.writepdfmarks {    % - .writepdfmarks <bool>
  20.   currentdevice //.writepdfmarkdict .getdeviceparams
  21.   mark eq { false } { pop pop true } ifelse
  22.   systemdict /DOPDFMARKS known or 
  23. } bind def
  24.  
  25. % For simplicity, we use a single interpretation dictionary for all
  26. % PDF graphics execution, even though this is too liberal.
  27. /pdfopdict mark
  28.   objopdict { } forall
  29.   drawopdict { } forall
  30.   /endstream { exit } bind
  31.   (%%EOF) cvn { exit } bind        % for filters
  32.     % PDF 1.1 operators
  33.   /BX { /BXlevel BXlevel 1 add store } bind
  34.   /EX { /BXlevel BXlevel 1 sub store } bind
  35.   /PS { cvx exec } bind
  36.     % PDF 1.2 operators
  37.   /BMC { pop } bind
  38.   /BDC { pop pop } bind
  39.   /EMC { }
  40.   /MP { pop } bind
  41.   /DP { pop pop } bind
  42. .dicttomark readonly def
  43.  
  44. % ======================== Main program ======================== %
  45.  
  46. end            % pdfdict
  47. userdict begin
  48.  
  49. /defaultfontname /Times-Roman def
  50.  
  51. % Make sure the registered encodings are loaded, so we don't run the risk
  52. % that some of the indices for their names will overflow the packed
  53. % representation.  (Yes, this is a hack.)
  54. SymbolEncoding pop
  55. DingbatsEncoding pop
  56.  
  57. % Redefine 'run' so it recognizes PDF files.
  58. systemdict begin
  59. /.runps /run load def
  60. /runpdfstring 50 string def        % length is arbitrary
  61. /run {
  62.   dup type /filetype ne { (r) file } if
  63.   dup ( ) .peekstring {
  64.     (%) eq {
  65.       dup (  ) .peekstring {
  66.     (%P) eq {
  67.       dup //runpdfstring {
  68.         % Some invalid files might have extra-long first lines....
  69.         { readline } .internalstopped not { pop pop exit } if
  70.         pop =string
  71.       } loop
  72.       //runpdfstring (%PDF-) anchorsearch {
  73.         pop pop runpdf
  74.       } {
  75.         pop cvx .runexec
  76.       } ifelse
  77.     } {
  78.       cvx .runps
  79.     } ifelse
  80.       } {
  81.     closefile
  82.       } ifelse
  83.     } {
  84.       cvx .runps
  85.     } ifelse
  86.   } {
  87.     closefile
  88.   } ifelse
  89. } bind odef
  90. currentdict /runpdfstring .undef
  91.  
  92. /runpdf            % <file> runpdf -
  93.  { userdict begin
  94.    /Page# null def
  95.    /Page null def
  96.    /DSCPageCount 0 def
  97.    /PDFSave null def
  98.    GS_PDF_ProcSet begin
  99.    pdfdict begin
  100.    pdfopen begin
  101.    Trailer /Root oget /Pages oget /CropBox knownoget
  102.     { mark /CropBox 3 -1 roll /PAGES pdfmark
  103.     }
  104.    if
  105.    /FirstPage where 
  106.     { pop FirstPage dup pdfpagecount gt
  107.       { (\nRequested FirstPage is greater than the number of pages in the file: ) print
  108.         pdfpagecount = flush
  109.       } if
  110.     } {
  111.       1
  112.     } ifelse
  113.    1
  114.    /LastPage where { pop LastPage pdfpagecount .min } { pdfpagecount } ifelse
  115.    2 index 1 index gt
  116.     { (   No pages will be processed \(FirstPage > LastPage\).) = flush }
  117.     { QUIET not
  118.       { (Processing pages ) print 2 index =only ( through ) print dup =only
  119.         (.) = flush
  120.       }
  121.      if
  122.     }
  123.    ifelse
  124.     { dup /Page# exch store
  125.       QUIET not { (Page ) print dup == flush } if
  126.       pdfgetpage pdfshowpage
  127.     } for
  128.    currentdict pdfclose
  129.    end            % temporary dict
  130.    end            % pdfdict
  131.    end            % userdict
  132.  } bind def
  133. end            % systemdict
  134. % Redefine the procedure that the C code uses for running piped input.
  135. % It is OK to use { (%stdin) run } here, because a startjob cannot occur.
  136. /.runstdin {
  137.   { (%stdin) run } execute0
  138. } bind def
  139.  
  140. end            % userdict
  141. pdfdict begin
  142.  
  143. % ======================== File parsing ======================== %
  144.  
  145. % Read the cross-reference and trailer sections.
  146.  
  147. /traileropdict mark
  148.   (<<) cvn { mark } bind
  149.   (>>) cvn /.dicttomark load
  150.   ([) cvn { mark } bind        % ditto
  151.   (]) cvn dup load
  152. %  /true true        % see .pdfexectoken in pdf_base.ps
  153. %  /false false        % ibid.
  154. %  /null null        % ibid.
  155.   /R { /resolveR cvx 3 packedarray cvx } bind    % see Objects below
  156.   /startxref /exit load
  157. .dicttomark readonly def
  158.  
  159. % Because of EOL conversion, lines with fixed contents might be followed
  160. % by one or more blanks.
  161. /lineeq            % <filestr> <conststr> lineeq <bool>
  162.  { anchorsearch
  163.     { pop { ( ) anchorsearch not { () eq exit } if pop } loop }
  164.     { pop false }
  165.    ifelse
  166.  } bind def
  167. /linene { lineeq not } bind def
  168.  
  169. % Read (mostly scan) the cross-reference table.
  170. /readxref        % <pos> readxref <trailerdict>
  171.  { PDFoffset add PDFfile exch setfileposition
  172.         % In some PDF files, this position actually points to
  173.         % white space before the xref line.  Skip over this here.
  174.    { PDFfile fileposition PDFfile read pop 32 gt { exit } if pop
  175.    } loop
  176.    PDFfile exch setfileposition
  177.         % The PDF specification says that the 'xref' must be on a line
  178.         % by itself. The code here formerly used readline and linene to
  179.         % check this. However, Acrobat Reader only requires the line to
  180.         % begin with 'xref', and there are enough applications producing
  181.         % non-compliant PDF files that we have to do this too.
  182.    PDFfile pdfstring 0 4 getinterval readstring pop
  183.    (xref) ne { /readxref cvx /syntaxerror signalerror } if
  184.         % Store the xref table entry position for each object.
  185.         % We only need to read the run headers, not every entry.
  186.     { PDFfile token pop        % first object # or trailer
  187.       dup /trailer eq { pop exit } if
  188.       PDFfile pdfstring readline pop
  189.       token pop            % entry count
  190.       exch pop exch
  191.         % This section might be adding new objects:
  192.         % ensure that Objects and Generations are big enough.
  193.         % Stack: count obj#
  194.       2 copy add growPDFobjects
  195.       PDFfile fileposition 3 -1 roll
  196.        { Objects 2 index lget null eq    % later update might have set it
  197.       { Objects 2 index 2 index cvx lput }
  198.          if exch 1 add exch 20 add
  199.        }
  200.       repeat PDFfile exch setfileposition pop
  201.     } loop
  202.    count /pdfemptycount exch def
  203.    PDFfile traileropdict .pdfrun
  204.  } bind def
  205.  
  206. % Open a PDF file and read the header, trailer, and cross-reference.
  207. /pdfopen {        % <file> pdfopen <dict>
  208.   pdfopenfile begin
  209.   pdfopencache
  210.   .writepdfmarks {
  211.     % Copy bookmarks (outline) to the output.
  212.     Trailer /Root oget /Outlines knownoget {
  213.       /First knownoget {
  214.     { dup writeoutline /Next knownoget not { exit } if } loop
  215.       } if
  216.     } if
  217.   } if        % end .writepdfmarks
  218.   currentdict end
  219. } bind def
  220. /pdfopencache {        % - pdfopencache -
  221.     % Create and initialize some caches.
  222.   /PageCount pdfpagecount def
  223.   /PageNumbers PageCount 65534 min dict def
  224.   /PageIndex PageCount 65534 min array def
  225. } bind def
  226. /pdfopenfile {        % <file> pdfopenfile <dict>
  227.    pdfdict readonly pop        % can't do it any earlier than this
  228.    15 dict begin
  229.    /LocalResources 0 dict def
  230.    /DefaultMatrix null def    % establish binding
  231.    /Printed where { pop } {
  232.         % Guess whether the output device is a printer.
  233.      /Printed currentpagedevice /OutputFile known def
  234.    } ifelse
  235.    /PSLevel1 where { pop } { /PSLevel1 false def } ifelse
  236.    cvlit /PDFfile exch def
  237.    /PDFsource PDFfile def
  238.    /Repaired false def
  239.    PDFfile dup 0 setfileposition pdfstring readstring 
  240.    not {/pdfopen cvx /syntaxerror signalerror} if
  241.    (%PDF-) search not {/pdfopen cvx /syntaxerror signalerror} if
  242.    length /PDFoffset exch def pop cvr /PDFversion exch def
  243.    findxref
  244.    initPDFobjects
  245.     % Read the last cross-reference table.
  246.    readxref /Trailer exch def
  247.    Trailer /Encrypt known
  248.     { pdf_process_Encrypt    % signal error
  249.     }
  250.    if
  251.     % Read any previous cross-reference tables.
  252.    Trailer { /Prev .knownget not { exit } if readxref } loop
  253.    Repaired { printrepaired } if
  254.    currentdict end
  255.  } bind def
  256.  
  257. % Skip backward over the %%EOF at the end of the PDF file, and read
  258. % the preceding startxref line.  The PDF specification unambiguously
  259. % requires that the %%EOF appear on a line by itself, and that the
  260. % startxref and the following position value appear on separate lines;
  261. % however, some applications (including, apparently, Acrobat Distiller
  262. % on the Macintosh) may add up to 2K of garbage after the %%EOF, and some
  263. % other applications also truncate the %%EOF to %%EO, and/or put the
  264. % startxref and the following value on the same line.
  265. % A file reported from Distiller 3.02b for AIX 4.1.1 has 2076 bytes
  266. % of garbage. The tolerance is increased to 4K to cover future
  267. % applications and bigger allocation units.
  268. /findxref {        % - findxref <xrefpos>
  269.   PDFfile dup dup 0 setfileposition bytesavailable
  270.   dup /PDFfilelen exch def
  271.     % Find the last %%EOF string (within 4096 bytes)
  272.   4096 sub PDFoffset .max
  273.   2 copy setfileposition
  274.   PDFfilelen exch sub string 1 index exch readstring pop {
  275.     (\015%%EO) search {        % Adobe can handle truncated key string
  276.       pop pop            % if found, keep searching 'post' string
  277.     } {
  278.       (\012%%EO) search
  279.     { pop pop } { exit } ifelse    % exit if neither string found
  280.     } ifelse
  281.   } loop
  282.   PDFfilelen exch length sub 4 sub PDFoffset .max exch 1 index setfileposition
  283.     % Stack: eofpos
  284.     % Check for whether this is, in fact, a valid PDF file.
  285.   dup PDFfilelen exch sub dup dup 7 gt exch 6 lt or {
  286.     pop true
  287.   } {
  288.     string PDFfile exch readstring pop
  289.     dup (%%EOF\n) eq exch dup (%%EOF\r) eq
  290.     exch (%%EOF\r\n) eq or or not
  291.   } ifelse {
  292.     (
  293.    **** This file has a corrupted %%EOF marker, or garbage after the %%EOF.
  294. ) pdfformaterror
  295.   } if
  296.   PDFfile exch setfileposition
  297.     % Now read the startxref and xref start position.
  298.   prevline token not { null } if dup type /integertype eq {
  299.     exch pop cvi        % xref start position
  300.     exch PDFfile exch setfileposition
  301.     prevline (startxref) linene { /findxref cvx /syntaxerror signalerror } if
  302.     pop
  303.   } {    % else, this file has 'startxref #####' format
  304.     (startxref) ne { /findxref cvx /syntaxerror signalerror } if
  305.     cvi        % xref start position
  306.     (
  307.    **** The format of the startxref line in this file is invalid.
  308. ) pdfformaterror
  309.     exch PDFfile exch setfileposition
  310.   } ifelse
  311. } bind def
  312. /stderrfile (%stderr) (w) file def
  313. /stderrprint {                % <string> stderrprint -
  314.   //stderrfile dup 3 -1 roll writestring flushfile
  315. } bind def
  316. /pdfformaterror {    % <string> pdfformaterror -
  317.   stderrprint
  318.   /Repaired true store
  319. } bind def
  320. /printrepaired {
  321.   Trailer /Info knownoget {
  322.     /Producer knownoget not { null } if
  323.   } {
  324.     null
  325.   } ifelse
  326.   dup null eq {
  327.     pop (\
  328.    **** Please notify the author of the software that produced this file
  329. )
  330.   } {
  331.     (   **** The file was produced by ) stderrprint
  332.     % Handle a Unicode Producer.
  333.     (\376\377) anchorsearch {
  334.       pop dup length 2 idiv string 0 1 2 index length 1 sub {
  335.         % Stack: origstr newstr i
  336.     1 index exch 3 index 1 index 2 mul 1 add get put
  337.       } for exch pop
  338.     } if
  339.     stderrprint
  340.     (:
  341.    **** please notify the author of this software
  342. )
  343.   } ifelse stderrprint
  344. (\
  345.    **** that the file does not conform to Adobe's published PDF
  346.    **** specification.  Processing of the file will continue normally.
  347.  
  348. ) stderrprint
  349. } bind def
  350.  
  351. % Write the outline structure for a file.  Uses linkdest (below).
  352. /writeoutline        % <outlinedict> writeoutline -
  353.  { mark
  354.    0 2 index /First knownoget
  355.     { { exch 1 add exch /Next knownoget not { exit } if } loop }
  356.    if
  357.         % stack: dict mark count
  358.    dup 0 eq
  359.     { pop 1 index
  360.     }
  361.     { 2 index /Count knownoget { 0 lt { neg } if } if
  362.       /Count exch 3 index
  363.     }
  364.    ifelse linkdest /Title oget /Title exch /OUT pdfmark
  365.    /First knownoget
  366.     { { dup writeoutline /Next knownoget not { exit } if } loop }
  367.    if
  368.  } bind def
  369.  
  370. % Close a PDF file.
  371. /pdfclose        % <dict> pdfclose -
  372.  { begin
  373.    PDFfile closefile
  374.    end
  375.  } bind def
  376.  
  377. % ======================== Page accessing ======================== %
  378.  
  379. % Get a (possibly inherited) attribute of a page.
  380. /pget            % <pagedict> <key> pget <value> -true-
  381.             % <pagedict> <key> pget -false-
  382.  { 2 copy knownoget
  383.     { exch pop exch pop true
  384.     }
  385.     { exch /Parent knownoget
  386.        { exch pget }
  387.        { pop false }
  388.       ifelse
  389.     }
  390.    ifelse
  391.  } bind def
  392.  
  393. % Get the value of a resource on a given page.
  394. /rget {            % <resname> <pagedict> <restype> rget <value> -true-
  395.             % <resname> <pagedict> <restype> rget -false-
  396.   LocalResources 1 index knownoget {
  397.      3 index knownoget
  398.   } {
  399.     false
  400.   } ifelse {
  401.     exch pop exch pop exch pop true
  402.   } {
  403.     exch /Resources pget {
  404.       exch knownoget { exch knownoget } { pop false } ifelse
  405.     } {
  406.       pop pop false
  407.     } ifelse
  408.   } ifelse
  409. } bind def
  410.  
  411. % Get the total number of pages in the document.
  412. /pdfpagecount        % - pdfpagecount <int>
  413.  { Trailer /Root oget /Pages oget /Count oget
  414.  } bind def
  415.  
  416. % Find the N'th page of the document by iterating through the Pages tree.
  417. % The first page is numbered 1.
  418. /pdffindpageref {        % <int> pdffindpage <objref>
  419.   dup Trailer /Root oget /Pages get
  420.     {        % We should be able to tell when we reach a leaf
  421.         % by finding a Type unequal to /Pages.  Unfortunately,
  422.         % some files distributed by Adobe lack the Type key
  423.         % in some of the Pages nodes!  Instead, we check for Kids.
  424.       dup oforce /Kids knownoget not { exit } if
  425.       exch pop null
  426.       0 1 3 index length 1 sub {
  427.          2 index exch get
  428.      dup oforce dup /Kids known { /Count oget } { pop 1 } ifelse
  429.         % Stack: index kids null noderef count
  430.      dup 5 index ge { pop exch pop exit } if
  431.      5 -1 roll exch sub 4 1 roll pop
  432.       } for exch pop
  433.         % Stack: index null|noderef
  434.       dup null eq { pop pop 1 null exit } if
  435.     } loop
  436.         % Stack: index countleft noderef
  437.    1 index 1 ne { pop pop /pdffindpage cvx /rangecheck signalerror } if
  438.    exch pop
  439.    PageIndex 2 index 1 sub 65533 min 2 index oforce put
  440.    PageNumbers 1 index oforce 3 index dup 65534 le
  441.     { put }
  442.     { pop pop pop }    % don't store more than 65534 pagenumbers
  443.    ifelse
  444.    exch pop
  445. } bind def
  446. /pdffindpage {        % <int> pdffindpage <pagedict>
  447.   pdffindpageref oforce
  448. } bind def
  449.  
  450. % Find the N'th page of the document.
  451. % The first page is numbered 1.
  452. /pdfgetpage        % <int> pdfgetpage <pagedict>
  453.  { PageIndex 1 index 1 sub dup 65533 lt
  454.     { get }
  455.     { pop pop null }
  456.    ifelse
  457.    dup null ne
  458.     { exch pop oforce }
  459.     { pop pdffindpage }
  460.    ifelse
  461.  } bind def
  462.  
  463. % Find the page number of a page object (inverse of pdfgetpage).
  464. /pdfpagenumber        % <pagedict> pdfpagenumber <int>
  465.  {    % We use the simplest and stupidest of all possible algorithms....
  466.    PageNumbers 1 index .knownget
  467.     { exch pop
  468.     }
  469.     { 1 1 PageCount 1 add    % will give a rangecheck if not found
  470.        { dup pdfgetpage oforce 2 index eq { exit } if pop
  471.        }
  472.       for exch pop
  473.     }
  474.    ifelse
  475.  } bind def
  476.  
  477. % Display a given page.
  478. /boxrect        % [<llx> <lly> <urx> <ury>] boxrect <x> <y> <w> <h>
  479.  { aload pop exch 3 index sub exch 2 index sub
  480.  } bind def
  481. /resolvedest {        % <name|string|other> resolvedest <other|null>
  482.   dup type /nametype eq {
  483.     Trailer /Root oget /Dests knownoget {
  484.       exch knownoget not { null } if
  485.     } {
  486.       null
  487.     } ifelse
  488.   } {
  489.     dup type /stringtype eq {
  490.       Trailer /Root oget /Names knownoget {
  491.     /Dests knownoget {
  492.       exch nameoget
  493.     } {
  494.       pop null
  495.     } ifelse
  496.       } {
  497.     pop null
  498.       } ifelse
  499.     } if
  500.   } ifelse
  501. } bind def
  502. /linkdest {        % <link|outline> linkdest
  503.             %   ([/Page <n>] /View <view> | ) <link|outline>
  504.   dup /Dest knownoget
  505.     { resolvedest
  506.       dup type /dicttype eq { /D knownoget not { null } if } if
  507.       dup null eq
  508.        { pop }
  509.        { dup 0 oget
  510.      dup null eq
  511.       { pop }
  512.       { dup type /integertype ne { pdfpagenumber } if
  513.         /Page exch 4 -2 roll
  514.       }
  515.      ifelse
  516.      dup length 1 sub 1 exch getinterval /View exch 3 -1 roll
  517.        }
  518.       ifelse
  519.     }
  520.    if
  521. } bind def
  522. % <pagedict> mark ... -proc- -
  523. /namedactions 8 dict dup begin
  524.   /FirstPage {
  525.     /Page 1 3 -1 roll
  526.   } def
  527.   /LastPage {
  528.     counttomark 2 add index pdfpagecount /Page exch 3 -1 roll
  529.   } def
  530.   /NextPage {
  531.     counttomark 2 add index pdfpagenumber 1 add /Page exch 3 -1 roll
  532.   } def
  533.   /PrevPage {
  534.     counttomark 2 add index pdfpagenumber 1 sub /Page exch 3 -1 roll
  535.   } def
  536. end readonly def
  537. % <pagedict> <annotdict> -proc- -
  538. /annottypes 5 dict dup begin
  539.   /Text {
  540.     mark exch
  541.      { /Rect /Open /Contents }
  542.      { 2 copy knownoget { 3 -1 roll } { pop } ifelse }
  543.     forall pop /ANN pdfmark
  544.   } bind def
  545.   /Link {
  546.     mark exch
  547.      { /Rect /Border }
  548.      { 2 copy knownoget { 3 -1 roll } { pop } ifelse }
  549.     forall dup /A knownoget {
  550.       dup /URI known {
  551.         /A mark 3 2 roll    % <<>> /A [ <<action>>
  552.         { oforce } forall
  553.         .dicttomark
  554.         3 2 roll
  555.       } {
  556.         dup /D knownoget {
  557.       exch pop exch dup length dict copy dup /Dest 4 -1 roll put
  558.         } {
  559.       /N knownoget {        % Assume /S /Named
  560.          namedactions exch .knownget { exec } if
  561.       } if
  562.         } ifelse
  563.       } ifelse
  564.     } if
  565.     linkdest pop /LNK pdfmark
  566.   } bind def
  567. end readonly def
  568.  
  569. /pdfshowpage        % <pagedict> pdfshowpage -
  570.  { dup /Page exch store
  571.    pdfshowpage_init 
  572.    pdfshowpage_setpage 
  573.    save /PDFSave exch store
  574.    (before exec) VMDEBUG
  575.      pdfshowpage_finish
  576.    (after exec) VMDEBUG
  577.    PDFSave restore
  578.  } bind def
  579.  
  580. /pdfpagecontents    % <pagedict> pdfpagecontents <contents>
  581.  { } bind def
  582.  
  583. /pdfshowpage_init     % <pagedict> pdfshowpage_init <pagedict>
  584.  { /DSCPageCount DSCPageCount 1 add store
  585.  } bind def
  586.  
  587. /.pdfshowpage_Install {    % <pagedict> [<prevproc>] .pdfshowpage_Install -
  588.   exch
  589.     % We would like to clip to the CropBox here, but the subsequent
  590.     % initgraphics would override it.  Instead, we have to handle it
  591.     % in graphicsbeginpage.
  592.   dup /MediaBox pget {
  593.     dup 0 get neg exch 1 get neg translate
  594.   } if
  595.   pop 0 get exec
  596. } bind def
  597.  
  598. /pdfshowpage_setpage {    % <pagedict> pdfshowpage_setpage <pagedict>
  599.   4 dict begin        % for setpagedevice
  600.     % Stack: pagedict
  601.   currentpagedevice /Orientation 2 index /Rotate pget not { 0 } if 90 idiv
  602.     % Rotate specifies *clockwise* rotation!
  603.     neg 3 and def
  604.     % Stack: pagedict currentpagedict
  605.   1 index /MediaBox pget {
  606.             % Set the page size.
  607.     boxrect 2 array astore /PageSize exch def pop pop
  608.   } if
  609.   dup /Install .knownget {
  610.             % Don't let the Install procedure get more deeply
  611.             % nested after every page.
  612.       dup type dup /arraytype eq exch /packedarraytype eq or {
  613.     dup length 4 eq {
  614.       dup 2 get /.pdfshowpage_Install load eq {
  615.         1 get 0 get    % previous procedure
  616.       } if
  617.     } if
  618.       } if
  619.   } {
  620.     { }
  621.   } ifelse 1 array astore
  622.   2 index exch /.pdfshowpage_Install load /exec load
  623.   4 packedarray cvx
  624.     % Stack: pagedict currentpagedict installproc
  625.   /Install exch def
  626.     % Stack: pagedict currentpagedict
  627.   pop currentdict end setpagedevice
  628. } bind def
  629.  
  630. /pdfshowpage_finish {    % <pagedict> pdfshowpage_finish -
  631.  
  632.   .writepdfmarks {
  633.  
  634.     % Copy the crop box.
  635.     dup /CropBox knownoget {
  636.     % If the page has been rotated, rotate the CropBox.
  637.       mark /CropBox 3 -1 roll
  638.       3 index /Rotate pget {
  639.     90 idiv 1 and 0 ne {
  640.       aload pop 4 -2 roll exch 4 2 roll exch 4 array astore
  641.     } if
  642.       } if
  643.       /PAGE pdfmark
  644.     } if
  645.  
  646.     % Copy annotations and links.
  647.     dup /Annots knownoget {
  648.       0 1 2 index length 1 sub
  649.        { 1 index exch oget
  650.          dup /Subtype oget annottypes exch .knownget { exec } { pop } ifelse
  651.        }
  652.       for pop
  653.     } if
  654.  
  655.   } if        % end .writepdfmarks
  656.  
  657.     % Display the actual page contents.
  658.    6 dict begin
  659.    /BXlevel 0 def
  660.    /BGDefault currentblackgeneration def
  661.    /UCRDefault currentundercolorremoval def
  662.     %****** DOESN'T HANDLE COLOR TRANSFER YET ******
  663.    /TRDefault currenttransfer def
  664.   matrix currentmatrix 2 dict
  665.   2 index /CropBox knownoget {
  666.     boxrect 4 array astore 1 index /ClipRect 3 -1 roll put
  667.   } if
  668.   dictbeginpage /DefaultMatrix 1 index store setmatrix
  669.   dup          % for showing annotations below
  670.   count /pdfemptycount exch store
  671.   gsave
  672.     % If the page uses any transparency features, show it within
  673.     % a transparency group.
  674.   PDFversion 1.4 lt {
  675.     showpagecontents
  676.   } {
  677.     dup pageusestransparency {
  678.       % Show the page within a PDF 1.4 device filter.
  679.       0 .pushpdf14devicefilter {
  680.     % If the page has a Group, enclose contents in transparency group.
  681.         % (Adobe Tech Note 5407, sec 9.2)
  682.         dup /Group knownoget {
  683.       1 index /CropBox knownoget not {
  684.         1 index /MediaBox oget
  685.       } if .beginformgroup {
  686.         showpagecontents
  687.       } .internalstopped {
  688.         .discardtransparencygroup stop
  689.       } if .endtransparencygroup
  690.         } {
  691.       showpagecontents
  692.         } ifelse
  693.       } .internalstopped {
  694.     % todo: discard
  695.     .popdevicefilter stop
  696.       } if .popdevicefilter
  697.     } {
  698.       showpagecontents
  699.     } ifelse
  700.   } ifelse
  701.   grestore
  702.    % todo: mixing drawing ops outside the device filter could cause
  703.    % problems, for example with the pnga device.
  704.    /Annots knownoget { { oforce drawannot } forall } if
  705.    endpage
  706.    end            % scratch dict
  707. } bind def
  708. /showpagecontents {    % <pagedict> showpagecontents -
  709.   /Contents knownoget not { 0 array } if
  710.   dup type /arraytype ne { 1 array astore } if {
  711.     oforce false resolvestream pdfopdict .pdfrun
  712.   } forall
  713. } bind def
  714. /processcolorspace {    % - processcolorspace <colorspace>
  715.     % The following is per the PLRM3.
  716.   currentdevice 1 dict dup /ProcessColorModel dup put .getdeviceparams
  717.   exch pop exch pop
  718.   dup type /nametype ne { cvn } if
  719.   dup { setcolorspace } .internalstopped { pop /DeviceRGB } if
  720. } bind def
  721.  
  722. % ------ Transparency support ------ %
  723.  
  724. % Determine whether a page might invoke any transparency features:
  725. %    - Group in the page dictionary
  726. %    - Non-default ca, CA, or SMask in an ExtGState
  727. %    - Form XObject with Group
  728. %    - Image XObject with SMask
  729. % ****** DO WE NEED TO LOOK IN RESOURCE DICTS OF OTHER CONTENT STREAMS? ******
  730. /pageusestransparency {        % <pagedict> pageusestransparency <bool>
  731.   PDFversion 1.4 lt {
  732.     pop false
  733.   } {
  734.     dup /Group known {
  735.       pop true
  736.     } {
  737.       false exch {
  738.     dup resourceusestransparency { pop not exit } if
  739.     /Parent knownoget not { exit } if
  740.       } loop
  741.     } ifelse
  742.   } ifelse
  743. } bind def
  744. % Check the Resources of a page or Form.
  745. /resourceusestransparency {    % <dict> resourceusestransparency <bool>
  746.   {    % Use loop to provide an exitable context.
  747.     /Resources knownoget not { 0 dict } if
  748.     dup /ExtGState knownoget {
  749.       false exch {
  750.     exch pop oforce
  751.     dup /ca knownoget { 1 ne { pop not exit } if } if
  752.     dup /CA knownoget { 1 ne { pop not exit } if } if
  753.     dup /SMask knownoget { /None ne { pop not exit } if } if
  754.     pop
  755.       } forall { pop true exit } if
  756.     } if
  757.     dup /XObject knownoget {
  758.       false exch {
  759.     exch pop oforce dup /Subtype get
  760.     dup /Image eq { 1 index /SMask known { pop pop not exit } if } if
  761.     /Form eq {
  762.       dup /Group known { pop not exit } if
  763.       resourceusestransparency { not exit } if
  764.     } {
  765.       pop
  766.     } ifelse
  767.       } forall { pop true exit } if
  768.     } if
  769.     pop false exit
  770.   } loop
  771. } bind def
  772.  
  773. end            % pdfdict
  774. .setglobal
  775.